/*
异步工作器的设计:
    1. 双缓冲区思想:
        - 任务数据-->"输入缓冲区"
        - "处理缓冲区"-->异步线程处理
实现:
成员:
    1. 双缓冲区(生产者消费者模型)
    2. 互斥锁(保证线程安全)
    3. 条件变量--唤醒线程
    4. 回调函数(如何处理数据)
操作:
    1. 停止异步工作器
    2. 添加数据到缓冲区
*/
#ifndef __M_LOOP_H__
#define __M_LOOP_H__

#include <vector>
#include <thread>
#include <mutex>
#include <atomic>
#include <functional>
#include <memory>
#include <condition_variable>
#include "buffer.hpp"

namespace LOG
{
    enum class AsyncType
    {
        ASYNC_SAFE,  // 安全状态, 缓冲区满了则阻塞, 避免资源耗尽
        ASYNC_UNSAFE // 不考虑资源问题, 用于极限性能测试
    };
    class AsyncLooper
    {
    public:
        using Func = std::function<void(Buffer &buf)>; // 回调函数-->定义了异步线程如何处理缓冲区中的数据
        using ptr = std::shared_ptr<AsyncLooper>;
        AsyncLooper(const Func &cb, AsyncType type = AsyncType::ASYNC_SAFE) : _looper_callback(cb), _running(true), _type(type),
                                                                              _thread(std::thread(&AsyncLooper::worker_loop, this))
        {
        }
        ~AsyncLooper()
        {
            stop();
        }
        void stop()
        {
            _running = false;       // 设置停止标志
            _pop_cond.notify_all(); // 唤醒所有的工作线程
            _thread.join();         // 等待工作线程退出
        }
        void push(const char *data, size_t len)
        {
            // 1. 无限扩容--用于极限性能测试
            // 2. 固定大小--生产缓冲区中数据满了--阻塞
            std::unique_lock<std::mutex> lock(_mutex);
            // 条件变量设置: 若缓冲区剩余空间大小大于数据长度, 则可以添加数据
            if (_type == AsyncType::ASYNC_SAFE)
                _push_cond.wait(lock, [&]()
                                { return _tasks_push.writeAbleSize() >= len; });
            // 说明: 可以向缓冲区中添加数据
            _tasks_push.push(data, len);
            _pop_cond.notify_one();
        }

    private:
        // 线程的入口函数
        void worker_loop()
        {
            while (1)
            {
                // 1. 判断生产者缓冲区有没有数据, 有则交换, 无则阻塞
                {
                    // 为互斥锁设置生命周期
                    std::unique_lock<std::mutex> lock(_mutex);
                    //当退出标志被设置 && 生产缓冲区中无数据, 退出循环
                    if(_running == false && _tasks_push.empty()) return;
                    _pop_cond.wait(lock, [&]()
                                   { return !_running || !_tasks_push.empty(); });
                    _tasks_pop.swap(_tasks_push);
                    // 2. 唤醒生产者
                    if (_type == AsyncType::ASYNC_SAFE)
                        _push_cond.notify_all();
                }
                // 3. 被唤醒后, 对消费者缓冲区进行数据处理
                _looper_callback(_tasks_pop);
                // 4. 初始化消费缓冲区
                _tasks_pop.reset();
            }
        }

    private:
        AsyncType _type;
        std::mutex _mutex;
        Func _looper_callback;              // 回调处理函数
        std::atomic<bool> _running;         // 是否停止异步工作器
        std::condition_variable _push_cond; // 唤醒输入缓冲区[生产者]
        std::condition_variable _pop_cond;  // 唤醒处理缓冲区[消费者]
        Buffer _tasks_push;                 // 输入缓冲区[生产者]
        Buffer _tasks_pop;                  // 处理缓冲区[消费者]
        std::thread _thread;                // 异步工作线程
    };
}

#endif